'''
Created on 09-09-05

@author: peterd
'''

# Manages CSE instances
#

import re, os
from datetime import datetime

from web.service.HttpReader import HttpReader, HttpDocumentNotFound, HttpReadError
from web.service.CSEBroker import CSEBroker
from lbc.models import *


class CSEAuthFailure(RuntimeError):
	def __init__(self, err):
		RuntimeError.__init__(self, err)


class CSEHandshakeFailure(RuntimeError):
	def __init__(self, err):
		RuntimeError.__init__(self, err)


class CSECreateFailure(RuntimeError):
	def __init__(self, err):
		RuntimeError.__init__(self, err)


class CSEManager:
	def __init__(self):
		pass
		'''
		try:
			authFile = open(os.path.join(os.environ['OREUS_HOME'], 'data/in/sk/lbc/cse.sid'))
			self.sid_ = authFile.read()
			authFile.close()
		except IOError:
			self.authenticate__()
		''' 
			

	# TODO: handle case when num CSE reaches defined watermark
	# remove the oldest idled CSE 
	def createCSEBroker(self, gobj, searchHandler, radius = -1, lang = 'sk'):
		httpReader = None
		searchEngine = None
		try:
			saName = ''
			if radius == -1:
				seName = '%s_%s' % (gobj.fullAsciiName(), lang)
			else:
				seName = '%s_%s_%s' % (gobj.fullAsciiName(), radius, lang)
			idle = SearchEngineStatus.objects.get(code = SearchEngineStatus.IDLE)
			inUse = SearchEngineStatus.objects.get(code = SearchEngineStatus.IN_USE)
			try:
				searchEngine = SearchEngine.objects.get(name = seName, status = idle)
			except SearchEngine.DoesNotExist:	
				sites = searchHandler.getSites()
				# get suitable agent		
				(sig, id, httpReader) = self.handshake__()
				if not sig or not id:
					self.authenticate__()
					(sig, id, httpReader) = self.handshake__()
					if not sig or not id:
						raise CSEHandshakeFailure('Failed to obtain cse signature or new engine id.')
					
				print '\n'.join(sites)					
									
				httpReader.addHeader('Content-type', 'application/x-www-form-urlencoded')
				response = httpReader.read('http://www.google.com/cse/manage/create?sig=%s' % sig, 
						{'description': 'gobj cse', 'edition': 'standard', 'id': id, 'language': lang,
			 			 'mode': 'restrict', 'name': seName, 't13n_language': '', 'tos': 'agree', 
			 			 'next': 'Suivant', 
			             'websites': '\n'.join(sites[:2000])
						})
										
				m = re.search('cx=(.*?)&', response)
				if not m:
					raise CSECreateFailure('Failed to obtain cx id.')
				
				searchEngine = SearchEngine()
				searchEngine.district = District.objects.get(ascii_name = 'none')
				searchEngine.location = Location.objects.get(street__ascii_name = 'none')
				gobj.toSearchEngine(searchEngine)
				searchEngine.name = seName
				searchEngine.cx_id = m.group(1)
				searchEngine.radius = radius
				searchEngine.created = datetime.today() 
				
			searchEngine.status = inUse
			searchEngine.last_use = datetime.today()
			searchEngine.save()
				
			return CSEBroker(searchEngine)
											
		except Exception, e:
			# TODO: log error
			raise
		
		
	def createSearchEngine(self, searchAgent, gobj, radius = -1, lang = 'sk'):
		httpReader = None
		searchEngine = None
		
		try:
			seName = ''
			if radius == -1:
				seName = '%s_%s' % (gobj.fullAsciiName(), lang)
			else:
				seName = '%s_%s_%s' % (gobj.fullAsciiName(), radius, lang)
			idle = SearchEngineStatus.objects.get(code = SearchEngineStatus.IDLE)
			inUse = SearchEngineStatus.objects.get(code = SearchEngineStatus.IN_USE)
			try:
				searchEngine = SearchEngine.objects.get(name = seName, status = idle)
			except SearchEngine.DoesNotExist:	
				if not searchAgent.sid:
					searchAgent.login()
				(sig, id, httpReader) = self.handshake__(searchAgent.sid)
				if not sig or not id:
					searchAgent.login()
					(sig, id, httpReader) = self.handshake__(searchAgent.sid)
					if not sig or not id:
						raise CSEHandshakeFailure('Failed to obtain cse signature or new engine id.')
									
				httpReader.addHeader('Content-type', 'application/x-www-form-urlencoded')
				response = httpReader.read('http://www.google.com/cse/manage/create?sig=%s' % sig, 
						{'description': 'gobj cse', 'edition': 'standard', 'id': id, 'language': lang,
			 			 'mode': 'restrict', 'name': seName, 't13n_language': '', 'tos': 'agree', 
			 			 'next': 'Suivant', 
			             'websites': 'foo.bar'
						})
										
				m = re.search('cx=(.*?)&', response)
				if not m:
					raise CSECreateFailure('Failed to obtain cx id.')
				
				cxId = m.group(1)
				
				httpReader = HttpReader()
				httpReader.addHeader('Cookie', searchAgent.sid)			
				response = httpReader.read('http://www.google.com/cse/panel/advanced?cx=%s&sig=%s' % (cxId, sig))
				
				m = re.search('<b>(_cse_.*?)</b>', response)
				if not m:
					raise CSECreateFailure('Failed to obtain cse include label.')
												
				searchEngine = SearchEngine()
				searchEngine.city = City.objects.get(ascii_name = 'none')
				searchEngine.district = District.objects.get(ascii_name = 'none')
				searchEngine.location = Location.objects.get(street__ascii_name = 'none')
				searchEngine.search_agent = searchAgent
				gobj.toSearchEngine(searchEngine)
				searchEngine.name = seName
				searchEngine.cx_id = cxId
				searchEngine.sig = sig
				searchEngine.include_label = m.group(1)
				searchEngine.num_sites = 0
				searchEngine.radius = radius
				searchEngine.created = datetime.today() 
				
			searchEngine.status = idle
			searchEngine.last_use = datetime.today()
			searchEngine.save()
				
			return searchEngine
											
		except Exception, e:
			# TODO: log error
			raise
		
		
	def handshake__(self, sid):
		sig = None
		id = None
		
		try:
			httpReader = HttpReader()
			httpReader.addHeader('Cookie', sid)			
			response = httpReader.read('http://www.google.com/coop/manage/cse/create/1')
			m = re.search('action=".*?\?sig=(.*?)"', response)
			if m:
				sig = m.group(1)
			m = re.search('<input type="hidden".* value="(.*?)"', response)
			if m:
				id = m.group(1)
			
			return (sig, id, httpReader)
		
		except Exception, e:
			# TODO: log exception
			raise CSEHandshakeFailure(e)

			
	def authenticate__(self):
		try:
			httpReader = HttpReader()
			httpReader.addHeader('Content-type', 'application/x-www-form-urlencoded')
			# TODO: read from a conf
			response = httpReader.read('https://www.google.com/accounts/ClientLogin',
							{'accountType': 'HOSTED_OR_GOOGLE', 
							 'Email': 'peter.dermek@yahoo.co.uk',
							 'Passwd': 'fezoj666',
							 'service': 'cprose',
							 'source': 'act-oreus-1.0'})
			m = re.search('(SID=.*)\n', response)
			if m:
				self.sid_ = m.group(1)
				authFile = open(os.path.join(os.environ['OREUS_HOME'], 'data/in/sk/lbc/cse.sid'), 'w')
				authFile.write(self.sid_)
				authFile.close()
			else:
				raise CSEAuthFailure('Expected Auth token, got %s' % response)  
		except Exception, e:
			# TODO: log exception
			raise CSEAuthFailure(e)
